extern screen_pixeles

%include "constantes.mac"

%define p_pantalla		 	[ebp - 4]

global negative

section .rodata
ceros:	dd 0x0, 0x0, 0x0, 0x0
unos:   dd 1.0, 1.0, 1.0, 1.0
dcc:	dd 255.0, 255.0, 255.0, 255.0

section .text

negative:
	push ebp			; creo el marco de la pila
	mov ebp, esp			; creo el marco de la pila
	
	push ebx			; salvo registros convencion C
	push edi			; salvo registros convencion C
	push esi			; salvo registros convencion C

	mov eax, [screen_pixeles]	; p_pantalla = screen_pixels
	mov p_pantalla, eax		; p_pantalla = screen_pixels

	mov ecx, ancho_pantalla_bytes	; inicializo indice del ciclo de filas
	shr ecx, 3			; inicializo indice del ciclo de filas
	sub ecx,100			; inicializo indice del ciclo de filas

	xor ebx, ebx			; contador filas totales

cicloFila:
	cmp ebx, 0
	je sigo
	mov eax, p_pantalla		 
	sub eax, ancho_pantalla_bytes	 
	movups xmm6, [eax]		; xmm6 = linea de px superior
sigo:
	mov eax, p_pantalla		
	movups xmm0, [eax]		; xmm0 = linea de px a modificar
	add eax, ancho_pantalla_bytes
	movups xmm7, [eax]		; xmm7 = linea de px inferior
	movaps xmm3, xmm0		; guardo referencia a xmm0
sumo_inf:	
	movaps xmm0, xmm7		; xmm0 => C(px) = inf(px)
unpackLinea:
	movaps xmm1, xmm0		
	punpcklbw xmm1, [ceros]		
	movaps xmm2, xmm0		
	punpckhbw xmm2, [ceros]		; tengo en xmm1 y xmm2 las words de xmm0
sumo_sup:
	jmp sumo_superior
	fin_sumo_superior:		; en xmm1 y xmm2 (bytes bajos y altos de xmm0) => C(px) = inf(px) + sup(px)

anterior: 
	jmp sumo_anterior		; sumo anterior agregando el pixel antes guardado
	fin_sumo_anterior:		; xmm1 y xmm2 => C(px) = ant(px) + inf(px) + sup(px) 

	jmp obtengo_pixel		; piso xmm5 con el nuevo pixel
	fin_obtengo_pixel:		; piso xmm5 con el nuevo pixel

siguiente:
	jmp sumo_siguiente
	fin_sumo_siguiente:		; xmm1 y xmm2 => C(px) = inf(px) + ant(px) + sup(px) + sgte(px)

calcs_float:
	jmp calculosPs
	fin_calculosPs:

	packuswb xmm1, xmm2		; empaqueto a byte (saturacion no signada)
	movaps xmm0, xmm1
	mov esi, p_pantalla		
	movdqu [esi], xmm0		; cambio cada color de pixel original por el calculo

sgte_linea:
	mov eax, p_pantalla
	add eax, 12
	mov p_pantalla, eax		; muevo puntero 12 bytes

loop cicloFila

cambio_de_fila:
	inc ebx				; incremento contador de filas
	xor ecx, ecx			; si itere alto_pantalla_bytes/2 termine de recorrer la pantalla
	mov ecx, alto_pantalla_bytes	; si itere alto_pantalla_bytes/2 termine de recorrer la pantalla
	shr ecx, 1			; si itere alto_pantalla_bytes/2 termine de recorrer la pantalla
	cmp ebx, ecx			; si itere alto_pantalla_bytes/2 termine de recorrer la pantalla
	je fin				; si itere alto_pantalla_bytes/2 termine de recorrer la pantalla

	mov eax, [screen_pixeles]	; p_pantalla = screen_pixels
	mov p_pantalla, eax		; p_pantalla = screen_pixels

	mov eax, ancho_pantalla_bytes	; muevo a la siguiente fila de la pantalla
	mul ebx				; muevo a la siguiente fila de la pantalla
	add p_pantalla, eax		; muevo a la siguiente fila de la pantalla

	mov ecx, ancho_pantalla_bytes	; restauro cantidad iteraciones en la fila
	shr ecx, 3			; restauro cantidad iteraciones en la fila
	sub ecx,100			; restauro cantidad iteraciones en la fila

	xorps xmm5, xmm5		; no hay pixel anterior a la primer linea

	jmp cicloFila			; itero sobre la fila

calculosPs:
	movaps xmm3, xmm1
	movaps xmm4, xmm2

	punpckhwd xmm3, [ceros]		; DW de words altas de xmm1
	punpcklwd xmm1, [ceros]		; DW de words bajas de xmm1
	punpckhwd xmm4, [ceros]		; DW de words altas de xmm2
	punpcklwd xmm2, [ceros]		; DW de words bajas de xmm2

	cvtdq2ps xmm1, xmm1
	cvtdq2ps xmm2, xmm2
	cvtdq2ps xmm3, xmm3
	cvtdq2ps xmm4, xmm4		; convierto a floats de simple precision

	movups xmm6, [dcc]		
	divps xmm1, xmm6
	divps xmm2, xmm6
	divps xmm3, xmm6
	divps xmm4, xmm6		; divido por 255
	
	movups xmm6, [unos]
	addps xmm1, xmm6
	addps xmm2, xmm6
	addps xmm3, xmm6
	addps xmm4, xmm6		; sumo 1

	rsqrtps xmm1, xmm1	
	rsqrtps xmm2, xmm2
	rsqrtps xmm3, xmm3
	rsqrtps xmm4, xmm4		; reciproca de raiz

	movups xmm6, [dcc]
	mulps xmm1, xmm6
	mulps xmm2, xmm6
	mulps xmm3, xmm6
	mulps xmm4, xmm6		; multiplico por 255

	cvttps2dq xmm1, xmm1
	cvttps2dq xmm2, xmm2
	cvttps2dq xmm3, xmm3
	cvttps2dq xmm4, xmm4		; convierto a enteros

	packssdw xmm1, xmm3
	packssdw xmm2, xmm4		; empaqueto de DW a W (saturacion signada)
jmp fin_calculosPs


sumo_superior:				; paddusb xmm0, xmm6
	movaps xmm7, xmm6
	punpcklbw xmm7, [ceros]		; xmm7 = 8W (de 8B bajas de xmm6)
	punpckhbw xmm6, [ceros]		; xmm7 = 8W (de 8B altas de xmm6)
	paddw xmm1, xmm7		; sumo low words en xmm1
	paddw xmm2, xmm6		; sumo high words en xmm2
jmp fin_sumo_superior


sumo_anterior:
	movaps xmm4, xmm3		; shift de xmm0_original a izquierda Y UNPCK A WORD!
	pslldq xmm4, 3
	paddb xmm4, xmm5		; completo pixel (como se lo sumo a 0 no es necesario el unpck)

	movaps xmm7, xmm4
	punpcklbw xmm7, [ceros]		; xmm7 = 8W (de 8B bajas de xmm4)
	punpckhbw xmm4, [ceros]		; xmm4 = 8W (de 8B altas de xmm4)
	paddw xmm1, xmm7		; sumo lows 
	paddw xmm2, xmm4		; sumo highs
jmp fin_sumo_anterior

sumo_siguiente:
	movaps xmm4, xmm3		; xmm4 = xmm0_original
	psrldq xmm4, 3	

	movaps xmm7, xmm4
	punpcklbw xmm7, [ceros]		; xmm7 = 8W (de 8B bajas de xmm4)
	punpckhbw xmm4, [ceros]		; xmm4 = 8W (de 8B altas de xmm4)
	paddw xmm1, xmm7		; sumo lows
	paddw xmm2, xmm4		; sumo highs
jmp fin_sumo_siguiente
obtengo_pixel:
	xor eax, eax			; obtengo mascara del ultimo pixel
	movaps xmm5, xmm3		; copia de xmm0 para la mascara del pixel
	mov eax, 0xFFFFFF00
	movd xmm7, eax
	pshufd xmm7, xmm7, 11001111b	; mascara en xmm7
	pand xmm5, xmm7			; obtengo el pixel
	psrldq xmm5, 9			; en xmm5 tengo los 3 bytes del ultimo pixel de la linea antes procesada
jmp fin_obtengo_pixel
fin:
	pop esi		; desarmo el stack frame
	pop edi		; desarmo el stack frame
	pop ebx		; desarmo el stack frame
	pop ebp		; desarmo el stack frame
	ret
